package com.zhdl.network.modbustcp.analysis;

import cn.hutool.core.util.HexUtil;
import com.project.command.faq.analysis.ComAnalysis;
import com.project.command.faq.analysis.ComAnalysisData;
import com.project.command.faq.analysis.ComAnalysisResult;
import com.zhdl.network.modbustcp.dto.ModbusTcpDto;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

@Slf4j
@Service(ModbusAnalysis.MODBUS_TCP_ANALYSIS)
public class ModbusAnalysis implements ComAnalysis<ModbusTcpDto, ByteBuf> {

    public static final String MODBUS_TCP_ANALYSIS = "modbus_tcp_1";

    ByteBuf buf = Unpooled.buffer();// 无限制长度


    /**
     * com原始返回数据,进行解析
     * 将ByteBuf 数据,转换为list初步解析对象
     * 接收示例数据 01 05 00 00 FF 00 8C 3A
     *
     * @param data
     * @return 可能多个数据包
     */
    @Override
    public ComAnalysisResult<ModbusTcpDto> analysisData(ComAnalysisData<ByteBuf> data) {
        List<ModbusTcpDto> fullFrames = new ArrayList<ModbusTcpDto>();
        try {
            // 循环读取数据流中的数据，一个字节一个字节的读取
            // mark当前Index，如果无法处理，则重置index，再有数据时仍然从头开始匹配
            buf = data.getBuf();
            buf.markReaderIndex();
            int breakCnt = 0;
            while (buf.isReadable()) {
                buf.readBytes(breakCnt);   // 跳过上次循环读的n个字节
                breakCnt++;
                // 判断是否满足字节最小数目,不满足直接return等待数据到来
                if (buf.readableBytes() < 7) {
                    log.info("读取数据长度小于最小长度");
                    buf.resetReaderIndex();
                    buf.clear();
                    return new ComAnalysisResult<>(fullFrames);
                }
                ModbusTcpDto ModbusTcpDto = new ModbusTcpDto();
                // 记录读取Index
                int readIndex = buf.readerIndex();


                buf.readBytes(6);
                // 读一个字节判断，一次只读一个字节，无法处理时读下一个字节，能正常解析时，读完整数据包的长度
                ModbusTcpDto.setAddress(buf.readByte()); // 地址

                byte cmdType = buf.readByte(); // 功能码
                ModbusTcpDto.setCmdType(cmdType);

                if (cmdType == (byte) 0x01 || cmdType == (byte) 0x05 || cmdType == (byte) 0x06) {
                    // 内存地址
                    byte[] addBuff = new byte[2];
                    buf.readBytes(addBuff);    //
                    // 数据
                    byte[] unitBuff = new byte[2];
                    buf.readBytes(unitBuff);
                    ModbusTcpDto.setUnitBuff(unitBuff);
                } else if (cmdType == (byte) 0x10) {
                    byte[] unitBuff = new byte[4];
                    buf.readBytes(unitBuff);
                    ModbusTcpDto.setUnitBuff(unitBuff);
                } else if (cmdType == (byte) 0x03) {
                    byte length = buf.readByte();
                    byte[] unitBuff = new byte[length];
                    buf.readBytes(unitBuff);
                }
                ByteBuffer fullFrame = ByteBuffer.allocate(buf.readerIndex() - readIndex);
                buf.getBytes(readIndex, fullFrame);
                ModbusTcpDto.setFullBuff(fullFrame.array());

                fullFrames.add(ModbusTcpDto);
                breakCnt = 0;
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            buf.clear();
            return new ComAnalysisResult<>(fullFrames);
        }
        log.info("return ComAnalysisResult>>>>>>>>>>>>>>>");
        return new ComAnalysisResult<>(fullFrames);
    }


    /**
     * 获取协议头信息
     *
     * @return
     */
    @Override
    public String getHeadAnalysis() {
        return "";
    }

    /**
     * 协议追加校验位信息（尾部数据）
     *
     * @param cmdStr
     * @return
     */
    @Override
    public byte[] getAfterAnalysis(String cmdStr) {
        return HexUtil.decodeHex(cmdStr);
    }
}
